#include <stdlib.h>
#include <glib.h>
#include <gtk/gtk.h>
#include <gdk/gdkx.h>
#include <gdk/gdkkeysyms.h>
#include <SDL.h>
#include "racanhack.h"
#include "task.h"
#include "video.h"
#include "cave.h"
#include "player.h"
#include "game.h"
#include "g2mesg.h"
#include "main.h"

static GtkWidget *messageWin;

static gboolean delete_event(GtkWidget *widget, GdkEvent  *event, gpointer data);
static void destroy(GtkWidget *widget, gpointer data);
static gboolean idle_loop(gpointer data);
static gboolean key_press_event(GtkWidget *widget, GdkEventKey *event);
static gboolean key_release_event(GtkWidget *widget, GdkEventKey *event);
static gboolean draw_value_bar(GtkWidget *widget, GdkEventExpose *event, gpointer data);

static gboolean delete_event(GtkWidget *widget, GdkEvent  *event, gpointer data)
{
  return FALSE;
}

static void destroy(GtkWidget *widget, gpointer data)
{
  gtk_main_quit();
}

static gboolean key_press_event(GtkWidget *widget, GdkEventKey *event)
{
  guint keyval;
  keyval = gdk_keyval_to_lower(event->keyval);
  switch (keyval) {
  case GDK_a: keys[SDLK_a] = TRUE; break;
  case GDK_b: keys[SDLK_b] = TRUE; break;
  case GDK_c: keys[SDLK_c] = TRUE; break;
  case GDK_d: keys[SDLK_d] = TRUE; break;
  case GDK_e: keys[SDLK_e] = TRUE; break;
  case GDK_f: keys[SDLK_f] = TRUE; break;
  case GDK_g: keys[SDLK_g] = TRUE; break;
  case GDK_h: keys[SDLK_h] = TRUE; break;
  case GDK_i: keys[SDLK_i] = TRUE; break;
  case GDK_j: keys[SDLK_j] = TRUE; break;
  case GDK_k: keys[SDLK_k] = TRUE; break;
  case GDK_l: keys[SDLK_l] = TRUE; break;
  case GDK_m: keys[SDLK_m] = TRUE; break;
  case GDK_n: keys[SDLK_n] = TRUE; break;
  case GDK_o: keys[SDLK_o] = TRUE; break;
  case GDK_p: keys[SDLK_p] = TRUE; break;
  case GDK_q: keys[SDLK_q] = TRUE; break;
  case GDK_r: keys[SDLK_r] = TRUE; break;
  case GDK_s: keys[SDLK_s] = TRUE; break;
  case GDK_t: keys[SDLK_t] = TRUE; break;
  case GDK_u: keys[SDLK_u] = TRUE; break;
  case GDK_v: keys[SDLK_v] = TRUE; break;
  case GDK_w: keys[SDLK_w] = TRUE; break;
  case GDK_x: keys[SDLK_x] = TRUE; break;
  case GDK_y: keys[SDLK_y] = TRUE; break;
  case GDK_z: keys[SDLK_z] = TRUE; break;
  case GDK_Shift_L: keys[SDLK_LSHIFT] = TRUE; break;
  case GDK_Shift_R: keys[SDLK_RSHIFT] = TRUE; break;
  case GDK_space: keys[SDLK_SPACE] = TRUE; break;
  case GDK_Return: keys[SDLK_RETURN] = TRUE; break;
  };
  return TRUE;
}

static gboolean key_release_event(GtkWidget *widget, GdkEventKey *event)
{
  guint keyval;
  keyval = gdk_keyval_to_lower(event->keyval);
  switch (keyval) {
  case GDK_a: keys[SDLK_a] = FALSE; break;
  case GDK_b: keys[SDLK_b] = FALSE; break;
  case GDK_c: keys[SDLK_c] = FALSE; break;
  case GDK_d: keys[SDLK_d] = FALSE; break;
  case GDK_e: keys[SDLK_e] = FALSE; break;
  case GDK_f: keys[SDLK_f] = FALSE; break;
  case GDK_g: keys[SDLK_g] = FALSE; break;
  case GDK_h: keys[SDLK_h] = FALSE; break;
  case GDK_i: keys[SDLK_i] = FALSE; break;
  case GDK_j: keys[SDLK_j] = FALSE; break;
  case GDK_k: keys[SDLK_k] = FALSE; break;
  case GDK_l: keys[SDLK_l] = FALSE; break;
  case GDK_m: keys[SDLK_m] = FALSE; break;
  case GDK_n: keys[SDLK_n] = FALSE; break;
  case GDK_o: keys[SDLK_o] = FALSE; break;
  case GDK_p: keys[SDLK_p] = FALSE; break;
  case GDK_q: keys[SDLK_q] = FALSE; break;
  case GDK_r: keys[SDLK_r] = FALSE; break;
  case GDK_s: keys[SDLK_s] = FALSE; break;
  case GDK_t: keys[SDLK_t] = FALSE; break;
  case GDK_u: keys[SDLK_u] = FALSE; break;
  case GDK_v: keys[SDLK_v] = FALSE; break;
  case GDK_w: keys[SDLK_w] = FALSE; break;
  case GDK_x: keys[SDLK_x] = FALSE; break;
  case GDK_y: keys[SDLK_y] = FALSE; break;
  case GDK_z: keys[SDLK_z] = FALSE; break;
  case GDK_Shift_L: keys[SDLK_LSHIFT] = FALSE; break;
  case GDK_Shift_R: keys[SDLK_RSHIFT] = FALSE; break;
  case GDK_space: keys[SDLK_SPACE] = FALSE; break;
  case GDK_Return: keys[SDLK_RETURN] = FALSE; break;
  };
  return TRUE;
}

static gboolean idle_loop(gpointer data)
{
  if (!main_player_running) {
    video_display();
    loopwait();
  };
  task_schedular();
  return TRUE;
}

int main(int argc, char *argv[])
{ 
  enum {G2_MIN_HP_LABEL_WIDTH = 65};
  GtkWidget *fixed;
  GtkWidget *hbox;
  GtkWidget *table;
  GtkWidget *eventbox;
  
  gtk_init (&argc, &argv);
  /* create a main window */
  main_window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
  gtk_widget_set_usize(GTK_WIDGET(main_window), DISPLAY_W, DISPLAY_H + 180);
  gtk_window_set_title(GTK_WINDOW(main_window), PACKAGE_STRING);
  gtk_container_set_border_width(GTK_CONTAINER(main_window), 10);
  g_signal_connect(G_OBJECT(main_window), "delete_event", G_CALLBACK (delete_event), NULL);
  g_signal_connect(G_OBJECT(main_window), "destroy", G_CALLBACK (destroy), NULL);
  g_signal_connect(G_OBJECT(main_window), "key_press_event", G_CALLBACK(key_press_event), NULL);
  g_signal_connect(G_OBJECT(main_window), "key_release_event", G_CALLBACK(key_release_event), NULL);

  fixed = gtk_fixed_new();
  hbox = gtk_hbox_new(FALSE, 10);
  table = gtk_table_new(2, 3, FALSE);

  gtk_fixed_put(GTK_FIXED(fixed), hbox, 0, DISPLAY_H);
  gtk_container_add(GTK_CONTAINER(main_window), fixed);

  eventbox = gtk_event_box_new();
  status_hp_bar = gtk_drawing_area_new();
  gtk_widget_set_size_request(status_hp_bar, -1, 10);
  g_signal_connect(G_OBJECT(status_hp_bar), "expose_event", G_CALLBACK(draw_value_bar), NULL);
  gtk_container_add(GTK_CONTAINER(eventbox), status_hp_bar);
  gtk_table_attach_defaults(GTK_TABLE(table), eventbox, 0, 1, 0, 1);

  eventbox = gtk_event_box_new();
  status_hp_label = gtk_label_new("HP 0/0\n");
  gtk_misc_set_alignment(GTK_MISC(status_hp_label), 0.0f, 0.5f);
  gtk_widget_set_size_request(status_hp_label, G2_MIN_HP_LABEL_WIDTH, -1);
  gtk_container_add(GTK_CONTAINER(eventbox), status_hp_label);
  gtk_table_attach_defaults(GTK_TABLE(table), eventbox, 0, 1, 1, 2);

  status_label = gtk_label_new("Dungeon Level 0. \n"
			       "LEVEL 0\n"
			       "STR 0/0\n"
			       "ATK 0 AC 0\n"
			       "FOOD 0\n");
  gtk_label_set_justify (GTK_LABEL (status_label), GTK_JUSTIFY_FILL);
  gtk_label_set_line_wrap (GTK_LABEL (status_label), TRUE);
  gtk_table_attach_defaults(GTK_TABLE(table), status_label, 0, 1, 2, 3);

  messageWin = g2_message_new();
  gtk_table_attach_defaults(GTK_TABLE(table), messageWin, 1, 2, 0, 3);
  gtk_box_pack_start(GTK_BOX(hbox), table, TRUE, FALSE, 0);

  gtk_widget_show_all(main_window);
  /* Hack to get SDL to use GTK window */
  {
    char SDL_windowhack[32];
    sprintf(SDL_windowhack,"SDL_WINDOWID=%ld", GDK_WINDOW_XWINDOW(main_window->window));
    putenv(SDL_windowhack);
  }

  SDL_init();
  video_sprite_init();
  video_flamme_init();
  task_init();
  main_player_running = FALSE;
  msg("%s", PACKAGE_STRING);
  gtk_idle_add(idle_loop, NULL);
  game_trans_state(game_opening, game_add());
  gtk_main();
  video_flamme_free();
  video_sprite_free();
  task_free();

  return 0;
}

void msg(const gchar *format, ...)
{
  enum {MAX_MSG_LENGTH = 128};
  gchar buf[MAX_MSG_LENGTH];
  va_list args;
  va_start(args, format);
  g_vsnprintf(buf, MAX_MSG_LENGTH, format, args);
  va_end(args);
  g_signal_emit_by_name(messageWin, "putstr", 0, buf, NULL);
}


static gboolean draw_value_bar(GtkWidget *widget, GdkEventExpose *event, gpointer data)
{
  static GdkGC *gc = NULL;
  static GdkColor hpColor = {0, 40 * 255, 133 * 255, 49 * 255};
  gint left = 0;
  gint top = 4;
  gint totalWidth;
  gint totalHeight;
  gint barWidth;
  gint barHeight;
  gfloat percent;
        
  if (!gc) {
    gc = gdk_gc_new(widget->window);
  }
  gdk_gc_set_rgb_fg_color(gc, &widget->style->bg[0]);
  gdk_draw_rectangle(widget->window, gc, TRUE, 0, 0,
		     widget->allocation.width, widget->allocation.height);
  percent = Player.chp / (gfloat) Player.mhp;
  gdk_gc_set_rgb_fg_color(gc, &hpColor);

  /* when you die */
  if (percent < 0) {
    percent = 0;
  }
  totalWidth = widget->allocation.width - left - 5;
  totalHeight = widget->allocation.height - (2 * top);
  barHeight = totalHeight - 3;
  barWidth = (totalWidth - 3) * percent;
  /* clear the bar */
  gdk_draw_rectangle(widget->window, gc, FALSE, left, top, totalWidth, totalHeight);
  gdk_draw_rectangle(widget->window, gc, TRUE, left + 2, top + 2, barWidth, barHeight);
 
  return TRUE;
}
